package ssi.staaar.managers;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;

import ssi.staaar.ciphers.AsymCipher;
import android.content.Context;
import encoders.Base64;

public class KeyManager {
	private Context activity;
	
	public KeyManager(Context context, String pwd) {
		this.activity=context;
	}

	public PublicKey getKeyFromByteArray(byte[] dec) {
		PublicKey decoded = null;
		byte[] decodedKey = Base64.decode(dec);
		KeyFactory keyFactory;
		try {
			keyFactory = KeyFactory.getInstance("RSA", "BC");
			EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(decodedKey);
			decoded = (PublicKey) keyFactory.generatePublic(publicKeySpec);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchProviderException e) {
			e.printStackTrace();
		} catch (InvalidKeySpecException e) {
			e.printStackTrace();
		}
		return decoded;
	}

	public void checkKeys(ArrayList<String> usernames) {
		usernames.add("Server.public");
		usernames.add("Local.private");
		usernames.add("Local.public");
		ArrayList<String> deleted = new ArrayList<String>();
		String[] keyFiles = this.activity.fileList();
		for (int i=0; i<keyFiles.length; ++i) {
			if (!usernames.contains(keyFiles[i]) && 
				!deleted.contains(keyFiles[i]) &&
				(keyFiles[i].contains(".private") || keyFiles[i].contains(".public"))) 
			{
				this.activity.deleteFile(keyFiles[i]);
				deleted.add(keyFiles[i]);
				i=0;
			}
		}
	}
	
	public void deleteKeyExcept(String except) {
		String[] keyFiles = this.activity.fileList();
		for (int i=0; i<keyFiles.length; ++i) {
			if (!keyFiles[i].contains(except))
				this.activity.deleteFile(keyFiles[i]);
		}
	}
	
	public PublicKey loadMyPublic() {
		return loadUserKey("Local");
	}

	public PrivateKey loadMyPrivate() {
		PrivateKey decoded = null;
		FileInputStream in = null;
		try {
			in = activity.openFileInput("Local.private");
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		}
		byte[] readedPrivate = new byte[1024];
		int inn; int i=0;
		try {
			while ((inn = in.read()) != -1) {
				readedPrivate[i] = (byte) inn;
				i++;
			}
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		try {
			in.close();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		byte[] decodedKey = Base64.decode(readedPrivate);
		KeyFactory keyFactory;
		try {
			keyFactory = KeyFactory.getInstance("RSA", "BC");
			EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(decodedKey);
			decoded = (PrivateKey) keyFactory.generatePrivate(privateKeySpec);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchProviderException e) {
			e.printStackTrace();
		} catch (InvalidKeySpecException e) {
			e.printStackTrace();
		}
		return decoded;
	}
	
	public PublicKey loadUserKey(String username) {
		PublicKey decoded = null;
		FileInputStream in = null;
		try {
			in = this.activity.openFileInput(username + ".public");
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		}
		byte[] readedPublic = new byte[255];
		int inn; int i=0;
		try {
			while ((inn = in.read()) != -1) {
				readedPublic[i] = (byte) inn;
				i++;
			}
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		try {
			in.close();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		byte[] decodedKey = Base64.decode(readedPublic);
		KeyFactory keyFactory;
		try {
			keyFactory = KeyFactory.getInstance("RSA", "BC");
			EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(decodedKey);
			decoded= (PublicKey) keyFactory.generatePublic(publicKeySpec);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchProviderException e) {
			e.printStackTrace();
		} catch (InvalidKeySpecException e) {
			e.printStackTrace();
		}
		return decoded;
	}
	
	public void removeUserKey(String username) {
		this.activity.deleteFile(username + ".public");
	}
	
	public void storeUserKey(String username, PublicKey key) {
		FileOutputStream os = null;
		try {
			os = this.activity.openFileOutput(username+ ".public", Context.MODE_PRIVATE);
			os.write(Base64.encode(key.getEncoded()));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				os.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public void storeMyPrivate(Key privateKey) {
		FileOutputStream os = null;
		try {
			os = this.activity.openFileOutput("Local.private", Context.MODE_PRIVATE);
			os.write(Base64.encode(privateKey.getEncoded()));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				os.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public void storeMyPublic(Key publicKey) {
		storeUserKey("Local", (PublicKey) publicKey);
	}

	public static void storeServerKey(String serverkey,Context context) {
		FileOutputStream os = null;
		try {
			os = context.openFileOutput("Server.public", Context.MODE_PRIVATE);
			os.write(Base64.encode(AsymCipher.getPubKeyFromString(serverkey).getEncoded()));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				os.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}	
	}
}
